package com.acme.javaschool.sems.ionio.net;

import com.acme.javaschool.sems.ionio.filetools.IoTools;
import com.acme.javaschool.sems.ionio.filetools.NioTools;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

import static java.lang.Math.min;
import static java.lang.Thread.sleep;

public class FileClient {

    private static final int CHUNK_SIZE = 32000;

    public void workIo(String fileToSendPath, String host, int port) {

        try (Socket socket = new Socket(host, port);
             DataInputStream in = new DataInputStream(socket.getInputStream());
             DataOutputStream out = new DataOutputStream(socket.getOutputStream());
             InputStream fileIn = new BufferedInputStream(new FileInputStream(fileToSendPath))
        ) {
            int bytesSentTotal = 0;
            int fileSize = fileIn.available();
            out.writeInt(CHUNK_SIZE);
            out.writeInt(fileSize);

            System.out.println("[client][workIo] transferring");
            while (bytesSentTotal < fileSize) {
                IoTools.transferChunkIo(fileIn, out, min(CHUNK_SIZE, fileSize - bytesSentTotal));
                int bytesReceivedByServerLast = in.readInt();
                bytesSentTotal += bytesReceivedByServerLast;
            }
            System.out.println("[client][workIo] Done.");
        } catch (IOException e) { e.printStackTrace(); }
    }

    public void workNio(String fileToSendPath, String host, int port) {

        try (
             SocketChannel socketChannel = SocketChannel.open();
             FileChannel fileChannel = new FileInputStream(fileToSendPath).getChannel();
        ) {
            System.out.println("[client][workNio] Started");
            socketChannel.connect(new InetSocketAddress(host, port));

            long fileSize = (int) fileChannel.size();
            long bytesSentTotal = 0;
            NioTools.writeLong(socketChannel, CHUNK_SIZE);
            NioTools.writeLong(socketChannel, fileSize);

            System.out.println("[client][workNio] Transferring...");
            while (bytesSentTotal < fileSize) {
                NioTools.readChunkFromFileAndSendNio(fileChannel, socketChannel, (int) min(CHUNK_SIZE, fileSize - bytesSentTotal));
                long bytesReceivedByServerLast = NioTools.readLong(socketChannel);
                bytesSentTotal += bytesReceivedByServerLast;
            }
            System.out.println("[client][workNio] Done.");
        } catch (IOException e) { e.printStackTrace(); }
    }

    public static void main(String... args) {
        System.out.println("[client] Started.");

        long startMillis = System.currentTimeMillis();

        if ("io".equals(args[0])) {
            new FileClient().workIo(args[1], args[2], Integer.valueOf(args[3]));
        } else if ("nio".equals(args[0])) {
            new FileClient().workNio(args[1], args[2], Integer.valueOf(args[3]));
        } else {
            System.out.println("[client] Unknown mode: " + args[0] + ".");
        }

        System.out.println("[client] TIME ELAPSED = " + (System.currentTimeMillis() - startMillis));
    }
}
